package com.dingwen.treasure.mybatisplus.util;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.dingwen.treasure.base.constant.RedisConstant;
import com.dingwen.treasure.base.enums.StatusEnum;
import com.dingwen.treasure.common.redis.service.RedisService;
import com.dingwen.treasure.model.entity.mybatisplus.SysConfig;
import com.dingwen.treasure.mybatisplus.service.SysConfigService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import javax.annotation.PostConstruct;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;

/**
 * 　SysConfigUtil
 * 　@author dingwen
 * 　@date 2022/6/3
 */
@Component
@Slf4j
@RequiredArgsConstructor
public class SysConfigUtil {

    /**
     * redis
     */
    private final RedisService redisService;

    /**
     * config service
     */
    private final SysConfigService sysConfigService;


    /**
     * 配置缓存
     */
    private static ConcurrentMap<String, String> SYS_CONFIG_CACHE;


    /**
     * 初始化： TODO JUC 优化
     */
    @PostConstruct
    public void init() {
        int count = sysConfigService.count();
        SYS_CONFIG_CACHE = MapUtil.newConcurrentHashMap(count + 1);
    }

    /**
     * 获取值
     *
     * @param key 钥匙
     * @return {@link String}
     */
    public String getValue(String key) {
        // key
        String fullKey = RedisConstant.SYS_CONFIG_PREFIX.concat(key.toLowerCase());

        // 从本地缓存中获取
        String value = SYS_CONFIG_CACHE.get(fullKey);

        if (StrUtil.isNotBlank(value)) {
            return value;
        }

        // 优化
        synchronized (this) {
            // 从redis中获取
            value = redisService.getCacheObject(fullKey);

            if (StrUtil.isNotBlank(value)) {
                // 放回本地内存缓存
                SYS_CONFIG_CACHE.put(fullKey, value);
                return value;
            }

            // 执行数据库查询
            return queryDb(key);
        }

    }

    /**
     * 获取值,指定默认值: 建议使用
     *
     * @param key          钥匙
     * @param defaultValue 默认值
     * @return {@link String}
     */
    public String getValueOrDefault(String key, String defaultValue) {
        return Convert.toStr(getValue(key), defaultValue);
    }


    /**
     * 刷新并获取值
     *
     * @param key 钥匙
     * @return {@link String}
     */
    public String refreshAndGetValue(String key) {
        String fullKey = RedisConstant.SYS_CONFIG_PREFIX.concat(key.toLowerCase());
        // 删除redis
        redisService.deleteObject(fullKey);
        // 删除本地缓存
        SYS_CONFIG_CACHE.remove(fullKey);

        // 此处空值不会存储到缓存中
        return queryDb(key);
    }


    /**
     * 刷新本地缓存
     *
     * @param configMap 配置映射
     */
    public void refreshLocalCache(Map<String, String> configMap) {
        SYS_CONFIG_CACHE.clear();
        SYS_CONFIG_CACHE.putAll(configMap);
    }


    /**
     * 查询数据库：此处加同步控制，防止不存在到key导致的大量的请求打到数据库
     *
     * @param key 钥匙
     * @return {@link String}
     */
    private synchronized String queryDb(String key) {
        LambdaQueryWrapper<SysConfig> lambdaQuery = new LambdaQueryWrapper<SysConfig>()
                .eq(SysConfig::getCode, key)
                .eq(SysConfig::getStatus, StatusEnum.NORMAL);
        SysConfig sysConfig = sysConfigService.getOne(lambdaQuery);

        if (ObjectUtils.isEmpty(sysConfig)) {
            return null;
        }

        String fullKey = RedisConstant.SYS_CONFIG_PREFIX.concat(key.toLowerCase());
        String value = sysConfig.getValue();

        // 存储到redis
        redisService.setCacheObject(fullKey, value);
        // 存储到内存
        SYS_CONFIG_CACHE.put(fullKey, value);
        return value;
    }
}
